package org.study.module.kerberos;

import org.study.module.common.ShellPre;

import java.util.ArrayList;
import java.util.List;

public class KerberosShell {

    /**
     * 修改主配置文件/etc/krb5.conf
     * 所有节点统一
     *
     * @param realm 域名
     * @param hostName KDC服务器主机名或IP
     */
    public static List<String> krb5Conf(String realm,String hostName) {
        List<String> commands = new ArrayList<>();
        commands.add("cat > /etc/krb5.conf << EOF");
        commands.add("[logging]");
        commands.add("default = FILE:/var/log/krb5libs.log");
        commands.add("kdc = FILE:/var/log/krb5kdc.log");
        commands.add("admin_server = FILE:/var/log/kadmind.log");
        commands.add("[libdefaults]");
        commands.add("dns_lookup_realm = false");
        //# 票据有效期
        commands.add("ticket_lifetime = 24h");
        //# 票据可续期时长
        commands.add("renew_lifetime = 7d");
        //# 允许票据转发
        commands.add("forwardable = true");
        commands.add("rdns = false");
        commands.add("pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt");
        commands.add("default_realm = " + realm.toUpperCase());
        commands.add("default_ccache_name = KEYRING:persistent:%{uid}");
        commands.add("[realms]");
        commands.add(realm.toUpperCase() + "={");
        commands.add("kdc = "+hostName+"  # KDC服务器主机名或IP");
        commands.add("admin_server = "+hostName+"  # 管理员服务器（通常与KDC同一节点）");
        commands.add("}");
        commands.add("[domain_realm]");
        commands.add("." + realm.toLowerCase() + " = " + realm.toUpperCase() + "  # 域名映射到Realm");
        commands.add(realm.toLowerCase() + " = " + realm.toUpperCase());
        commands.add("EOF");
        return commands;
    }

    /**
     * 配置 KDC 服务,只在部署了KDC的节点配置
     */
    public static List<String> kdcConf(String realm) {
        List<String> commands = new ArrayList<>();
        commands.add("cat > /var/kerberos/krb5kdc/kdc.conf << EOF");
        commands.add("[kdcdefaults]");
        commands.add("kdc_ports = 88");
        commands.add("kdc_tcp_ports = 88");
        commands.add("[realms]");
        commands.add(realm.toUpperCase() + "= {  # 与krb5.conf中的Realm一致");
        commands.add(" # 生成数据库时使用的加密算法（默认即可）");
        commands.add(" master_key_type = aes256-cts");
        commands.add(" acl_file = /var/kerberos/krb5kdc/kadm5.acl");
        commands.add(" dict_file = /usr/share/dict/words");
        commands.add(" admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab");
        commands.add(" #支持的加密类型");
        commands.add(" supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal");
        commands.add("}");
        commands.add("EOF");
        return commands;
    }

    /**
     * 管理员权限配置,允许admin/admin@EXAMPLE.COM管理所有权限
     * 仅在 KDC 服务器上配置
     *
     * @param realm 域名
     */
    public static List<String> kadm5Acl(String realm) {
        List<String> commands = new ArrayList<>();
        commands.add("cat >> /var/kerberos/krb5kdc/kadm5.acl << EOF");
        commands.add("*/admin@" + realm.toUpperCase() + "  *");
        commands.add("EOF");
        return commands;
    }

    /**
     * 初始化数据库，
     * @param password 初始化数据库的密码
     */
    public static List<String> kdbInit(String password) {
        List<String> commands = new ArrayList<>();
        commands.add("echo \"若需重新创建数据库，需先删除原有文件\"");
        commands.add("rm -f /var/kerberos/krb5kdc/principal* /var/kerberos/krb5kdc/.k5.*");
        commands.add("# 初始化数据库（-s生成stash文件存储密码）");
        commands.add("#kdb5_util create -s");
        commands.add("# 输入KDC数据库的管理员密码（记住此密码，后续管理需使用）");
        //密码自动化设置
        commands.add("echo \"" + password + "\" | kdb5_util create -s -P -");
        commands.add("# 执行后会生成数据库文件（默认路径/var/kerberos/krb5kdc/principal）");
        return commands;
    }

    /**
     * 创建 Kerberos 管理员主体
     */
    public static List<String> admin(String realm) {
        List<String> commands = new ArrayList<>();
        //语法：kadmin.local -q "addprinc -pw 密码 主体名"
        commands.add("kadmin.local -q \"addprinc -pw AdminPass123! admin/admin@EXAMPLE.COM\"");
        commands.add("# 启动kadmin.local（本地管理员工具）");
        commands.add("kadmin.local");
        commands.add("# 创建管理员主体（格式：用户名/admin@REALM）");
        commands.add("addprinc admin/admin@" + realm.toUpperCase());
        commands.add("# 输入密码（管理员密码）");
        commands.add("# 退出kadmin.local");
        commands.add("quit");
        return commands;
    }

    /**
     * 在 KDC 服务器上创建管理员主体（用于管理 Kerberos）
     * 仅在 KDC 服务器上配置
     *
     * @param realm 域名
     */
    public static List<String> admin(String realm, String password) {
        List<String> commands = new ArrayList<>();
        //语法：kadmin.local -q "addprinc -pw 密码 主体名"
        commands.add("kadmin.local -q \"addprinc -pw " + password + " admin/admin@" + realm.toUpperCase() + "\"");
        return commands;
    }

    /**
     * 在KDC服务商， 创建 Kerberos 创建用户主体
     * @param user 如果是hadoop集群则一般采用 组件角色/hostname
     * @param password 用户的密码
     * @param realm 域名
     */
    public static List<String> user(String user, String realm, String password) {
        List<String> commands = new ArrayList<>();
        //语法：kadmin.local -q "addprinc -pw 密码 主体名"
        commands.add("kadmin.local -q \"addprinc -pw " + password + " " + user + "@" + realm.toUpperCase() + "\"");
        return commands;
    }

    /**
     * 启动 Kerberos 服务并设置开机自启
     */
    public static List<String> systemctl() {
        List<String> commands = new ArrayList<>();
        commands.add("# 启动KDC和管理员服务");
        commands.add("systemctl start krb5kdc");
        commands.add("systemctl start kadmind");
        commands.add("# 设置开机自启");
        commands.add("systemctl enable krb5kdc");
        commands.add("systemctl enable kadmind");
        commands.add("# 检查服务状态");
        commands.add("systemctl status krb5kdc");
        commands.add("systemctl status kadmind");
        return commands;
    }

    /**
     * 配置防火墙
     */
    public static List<String> firewall() {
        List<String> commands = new ArrayList<>();
        commands.add("# 开放Kerberos端口（88：KDC，464：管理员服务）");
        commands.add("firewall-cmd --zone=public --add-port=88/tcp --permanent");
        commands.add("firewall-cmd --zone=public --add-port=464/tcp --permanent");
        commands.add("firewall-cmd --reload");
        return commands;
    }

    public static List<String> addUser(String user, String realm) {
        List<String> commands = new ArrayList<>();
        commands.add("#创建测试用户主体");
        commands.add("#kadmin.local -q \"addprinc testuser@EXAMPLE.COM\"");
        commands.add("kadmin.local -q \"addprinc " + user + "@" + realm.toUpperCase() + "\"");
        commands.add("#获取票据");
        commands.add("#kinit testuser@EXAMPLE.COM");
        commands.add("kinit " + user + "@" + realm.toUpperCase());
        commands.add("#查看票据");
        commands.add("klist");
        return commands;
    }

    /**
     * 生成HDFS开头的，keytab文件
     * @param uploadPath 上传路径
     * @param host 机器的hostname
     * @param realm 域名
     */
    public static String hdfsKeytab(String uploadPath, String host, String realm) {
        return "kadmin.local -q \"ktadd -k " + ShellPre.configPath(uploadPath) + "/hdfs-" + host + ".keytab hdfs/" + host + "@" + realm.toUpperCase() + "\"";
    }
    /**
     * 生成yarn开头的，keytab文件
     * @param uploadPath 上传路径
     * @param host 机器的hostname
     * @param realm 域名
     */
    public static String yarnKeytab(String uploadPath, String host, String realm) {
        return "kadmin.local -q \"ktadd -k " + ShellPre.configPath(uploadPath) + "/yarn-" + host + ".keytab yarn/" + host + "@" + realm.toUpperCase() + "\"";
    }
}
